#include <stdio.h>

#include <fcntl.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdio.h>
#include "osal_thread.h"


#include "hdf_sbuf.h"
#include "hdf_io_service_if.h"
#include "cJSON.h"



#define HDF_E53_IA1_SRV "hdf_e53_ia1"

double value[3];//存储温湿度光照的数据

typedef enum {
    E53_IA1_Start = 0,
    E53_IA1_Stop,
    E53_IA1_Read,
    E53_IA1_SetMotor,
    E53_IA1_SetLight,
    E53_IA1_FanLevel
}E53_IA1Ctrl;

 static int SendEvent(struct HdfIoService *serv,int32_t cmd, uint8_t *eventData,uint8_t dataLen)
{
    int ret = 0;
    
    struct HdfSBuf *data = HdfSBufObtainDefaultSize();
    if (data == NULL)
    {
        printf("fail to obtain sbuf data!\r\n");
        return 1;
    }

    struct HdfSBuf *reply = HdfSBufObtainDefaultSize();
    if (reply == NULL)
    {
        printf("fail to obtain sbuf reply!\r\n");
        ret = HDF_DEV_ERR_NO_MEMORY;
        goto out;
    }
    // /* 写入数据 *///三组API都能用,但是要注意对端使用什么方式接收,强类型
    // ret = HdfSbufWriteBuffer(data, eventData, dataLen);
    // ret = HdfSbufWriteUnpadBuffer(data, eventData, dataLen);
    ret = HdfSbufWriteString(data, eventData);
    if (ret != true)
    {
        printf("fail to write sbuf!\r\n");
        ret = HDF_FAILURE;
        goto out;
    }
    
    /* 通过Dispatch发送到驱动 */
    ret = serv->dispatcher->Dispatch(&serv->object, cmd, data, reply);
    if (ret != HDF_SUCCESS)
    {
        printf("fail to send service call!\r\n");
        goto out;
    }

    /* 读取驱动的回复数据 */
    char *val = (char *)(HdfSbufReadString(reply));
    if(val == NULL){
        printf("fail to get service call reply!\r\n");
        ret = HDF_ERR_INVALID_OBJECT;
        goto out;
    }
    printf("\r\nGet reply is: %s\r\n", val);
    //*       存储上传数据        *//
    if(cmd == E53_IA1_Read){
        printf("-------------------------> set  success \n ");
        cJSON* cjson =cJSON_Parse(val);
        double test_1_string = cJSON_GetObjectItem(cjson,"Temp")->valuedouble;
        double test_2_string = cJSON_GetObjectItem(cjson,"Hum")->valuedouble;
        double test_3_string = cJSON_GetObjectItem(cjson,"Lux")->valuedouble;
        value[0] = test_1_string;
        value[1] = test_2_string;
        value[2] = test_3_string;
    } 
out:
    HdfSBufRecycle(data);
    HdfSBufRecycle(reply);
    return ret;
}


#include "MQTTClient.h"


static unsigned char sendBuf[1000];
static unsigned char readBuf[1000];

#define HOST_ADDR "f717a521b9.iot-mqtts.cn-north-4.myhuaweicloud.com"  //mqtt的URL
#define PUBLISH_TOPIC "$oc/devices/1234peipei/sys/properties/report"
#define SUBCRIB_TOPIC "$oc/devices/1234peipei/sys/commands/#"  //request_id={request_id}"
#define RESPONSE_TOPIC "$oc/devices/1234peipei/sys/commands/response" ///request_id={request_id}"


Network network;
MQTTClient client;


void messageArrived(MessageData* data)
{
    int rc;
    int ret=0;
    /*                获取服务                  */
    struct HdfIoService *serv = HdfIoServiceBind(HDF_E53_IA1_SRV);
    printf("Message arrived on topic %.*s: %.*s\n", data->topicName->lenstring.len, data->topicName->lenstring.data,
           data->message->payloadlen, data->message->payload);
    
    char *request_id_idx=NULL;
    char request_id[48]={0};
    request_id_idx = strstr(data->topicName->lenstring.data,"request_id=");
    strncpy(request_id,request_id_idx+11,36);
    printf("request_id = %s\n",request_id);

    char rsptopic[128]={0};
    sprintf(rsptopic,"%s/request_id=%s",RESPONSE_TOPIC,request_id);
    printf("rsptopic = %s\n",rsptopic);

    //response message
    MQTTMessage message;
    char payload[300];
    message.qos = 0;
    message.retained = 0;
    message.payload = payload;
    
    //*      响应参数       *//
    sprintf(payload,"{\
        \"result_code\": 0,\
        \"response_name\": \"COMMAND_RESPONSE\",\
        \"paras\": {\
            \"result\": \"success\"\
    }");
    message.payloadlen = strlen(payload);

    if ((rc = MQTTPublish(&client,rsptopic, &message)) != 0) {
        printf("Return code from MQTT publish is %d\n", rc);
        NetworkDisconnect(&network);
        MQTTDisconnect(&client);

    }
    else{
        printf("mqtt publish succedss:%s\n",payload);
       
    }
    //*           用cjson解析数据       *//
    cJSON *root = cJSON_Parse(data->message->payload); //从长字符串中截取命令id,服务器id
    if(root ==NULL){
        return;
    }
     printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>ready to get in\n");

    cJSON *cmd_name_obj = cJSON_GetObjectItem(root,"command_name");//截取从command_name开始的数据
    if(cmd_name_obj){
        printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>get in first if\n");
        char *command_name=cJSON_GetStringValue(cmd_name_obj);
        if(command_name!=NULL){
                printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>get in second if\n");
            if(strcmp(command_name,"led_control")==0) //截取出命令id，判断是否是控制led灯的命令
            {
                cJSON *paras_obj = cJSON_GetObjectItem(root,"paras");//获得命令中的参数
                if(paras_obj!=NULL){
                    cJSON *led_obj=cJSON_GetObjectItem(paras_obj,"led");//从参数中截取LED的状态信息，ON/OFF
                    if(led_obj!=NULL){
                        char *led_cmd_str=cJSON_GetStringValue(led_obj);
                        if(strcmp(led_cmd_str,"ON")==0){
                            ret = SendEvent(serv, E53_IA1_SetLight,(uint8_t *)"ON",3);
                            printf("==> E53_IA1_SetLight = %d \n", ret);
                        }
                        else if(strcmp(led_cmd_str,"OFF")==0){
                           ret = SendEvent(serv, E53_IA1_SetLight,(uint8_t *)"OFF",3);
                           printf("==> E53_IA1_SetLight = %d \n", ret);
                        }
                    }
                }
            }
            else if(strcmp(command_name,"motor_control")==0)
            {
                printf(">>>>>>>>>>ready start motor\n");
                cJSON *paras_obj = cJSON_GetObjectItem(root,"paras");//获得命令中的参数
                if(paras_obj!=NULL){
                    cJSON *motor_obj=cJSON_GetObjectItem(paras_obj,"motor_onoff");//从参数中截取MOTOR的状态信息，ON/OFF
                    cJSON *motor_lev = cJSON_GetObjectItem(paras_obj, "motor_level");//从参数中截取MOTOR的转速信息[0-5]
                    if(motor_obj!=NULL){
                        char *motor_cmd_strs = cJSON_GetStringValue(motor_obj);
                        int motor_cmd_str=(int)cJSON_GetNumberValue(motor_lev);
                        if (strcmp(motor_cmd_strs,"ON") == 0){
                            ret = SendEvent(serv, E53_IA1_SetMotor,(uint8_t *)"ON",2);
                            printf("==> E53_IA1_SetMotor = %d \n", ret);
                            if(motor_cmd_str==0){
                                ret = SendEvent(serv,E53_IA1_FanLevel, (uint8_t *)"0",1);
                                printf("==> E53_IA1_SetMotor = %d \n", ret);
                            }
                            else if(motor_cmd_str==1){
                                ret = SendEvent(serv,E53_IA1_FanLevel, (uint8_t *)"1",1);
                                printf("==> E53_IA1_SetMotor = %d \n", ret);
                                printf(">>>>>>>>>>motor turn 1\n");
                                
                            }
                            else if(motor_cmd_str==2){
                                ret = SendEvent(serv,E53_IA1_FanLevel, (uint8_t *)"2",1);
                                printf("==> E53_IA1_SetMotor = %d \n", ret);
                                
                            }
                            else if(motor_cmd_str==3){
                                ret = SendEvent(serv,E53_IA1_FanLevel, (uint8_t *)"3",1);
                                printf("==> E53_IA1_SetMotor = %d \n", ret);
                                
                            }
                            else if(motor_cmd_str==4){
                                ret = SendEvent(serv,E53_IA1_FanLevel, (uint8_t *)"4",1);
                                printf("==> E53_IA1_SetMotor = %d \n", ret);
                            
                            }
                            else if(motor_cmd_str==5){
                                ret = SendEvent(serv,E53_IA1_FanLevel, (uint8_t *)"5",1);
                                printf("==> E53_IA1_SetMotor = %d \n", ret);
                                
                            }
                        }else if(strcmp(motor_cmd_strs,"OFF") == 0)
                            {
                            ret = SendEvent(serv, E53_IA1_SetMotor,(uint8_t *)"OFF",3);
                            printf("==> E53_IA1_SetMotor = %d \n", ret);                                  
                            }
                    }
                }

            }
        }
    }
    cJSON_Delete(root);
    
}

static void MQTTDemoTask(void)
{
    /*                获取服务                  */
    struct HdfIoService *serv = HdfIoServiceBind(HDF_E53_IA1_SRV);
    printf("Starting ...\n");
    int rc, count, ret= 0;
  
    NetworkInit(&network);
    printf("NetworkConnect  ...\n");
begin:
    NetworkConnect(&network, "121.36.42.100", 1883);
    printf("MQTTClientInit  ...\n");
    MQTTClientInit(&client, &network, 2000, sendBuf, sizeof(sendBuf), readBuf, sizeof(readBuf));

    /*    服务端所需数据   */
    MQTTString clientId = MQTTString_initializer;
    clientId.cstring = "1234peipei_0_0_2022070508";

    MQTTString userName = MQTTString_initializer;
    userName.cstring = "1234peipei";

    MQTTString password = MQTTString_initializer;
    password.cstring = "bca310c1009c63b19ab86b27eb99f567619d3bfe4cd6e5e761b3d94f421b6885";


    MQTTPacket_connectData data = MQTTPacket_connectData_initializer;//连接云平台需要的数据

    data.clientID = clientId;

    data.username = userName;
	data.password = password;

    data.willFlag = 0;
    data.MQTTVersion = 4;
    data.keepAliveInterval = 60;
    data.cleansession = 1;
    
    //*     连接mqtt      *//     
    printf("MQTTConnect  ...\n");
    rc = MQTTConnect(&client, &data);
    if (rc != 0) {
        printf("MQTTConnect: %d\n", rc);
        NetworkDisconnect(&network);
        MQTTDisconnect(&client);
        usleep(200);
        goto begin;
    }

    printf("MQTTSubscribe  ...\n");
    rc = MQTTSubscribe(&client, SUBCRIB_TOPIC, 0, messageArrived);
    if (rc != 0) {
        printf("MQTTSubscribe: %d\n", rc);
        usleep(200);
        goto begin;
    }
    while (1) {
        ret = SendEvent(serv,E53_IA1_Read,NULL,0);//从驱动获取传感器的数据
        MQTTMessage message;
        char payload[300];

        message.qos = 0;
        message.retained = 0;
        message.payload = payload;
        message.payloadlen = strlen(payload);
        /*       将数据进行cJSON打包上传到华为云        */
        cJSON *root = cJSON_CreateObject();//空的
        if(root != NULL){
            cJSON *service_array = cJSON_AddArrayToObject(root,"services");
            if(service_array != NULL){
                cJSON *service_item = cJSON_CreateObject();
                cJSON_AddStringToObject(service_item,"service_id","device_info");
                cJSON *properties_obj = cJSON_CreateObject();
                cJSON_AddNumberToObject(properties_obj,"Temp",value[0]);
                cJSON_AddNumberToObject(properties_obj,"Humi",value[1]);
                cJSON_AddNumberToObject(properties_obj,"Lux",value[2]);
                cJSON_AddItemToObject(service_item,"properties",properties_obj);
                cJSON_AddItemToArray(service_array,service_item);

            }
            
            char *payload_str=cJSON_PrintUnformatted(root);
            printf("");
            strcpy(payload,payload_str);
            cJSON_free(payload_str);


            cJSON_Delete(root);//释放内存

        }

        if ((rc = MQTTPublish(&client, PUBLISH_TOPIC, &message)) != 0) {
            printf("Return code from MQTT publish is %d\n", rc);
            NetworkDisconnect(&network);
            MQTTDisconnect(&client);
            goto begin;
        }else{
            printf("mqtt publish success:%s\n",payload);
        }
        MQTTYield(&client, 500);//阻塞程序，接受消息
    }
}

int main(int argc,char *argv[])
{
    int ret = 0;
    printf("hello !!\n");
    /*                获取服务                  */
    struct HdfIoService *serv = HdfIoServiceBind(HDF_E53_IA1_SRV);

    if(serv == NULL)//判定是否获取服务成功
    {
        printf("hdf_e53_ia1 Bind Failed\n");
        return -1;
    }

    //* 手动实现选择风扇强度、开关以及灯光控制   *//
    if(argc == 3){

        if(strcmp(argv[1],"fan_level")==0){
            int fan_level = atoi(argv[2]);
            printf("fan_level is %d\n",fan_level); 

            if( (fan_level>=0 )){

                ret = SendEvent(serv,E53_IA1_FanLevel, (uint8_t *)argv[2],strlen(argv[2]));
                printf("==> set fan level %d ret %d \n",fan_level, ret);
            }
             else{
                 printf("error: fan level must be [0-5]");
                 return 0;
            }


        }else if(strcmp(argv[1],"led")==0){
            if( (strcmp(argv[2],"ON")== 0 )|| (strcmp(argv[2],"OFF")==0 )){
                
                ret = SendEvent(serv,E53_IA1_SetLight, (uint8_t *)argv[2],3);
                printf("==> E53_IA1_SetLight = %d \n", ret);                

            }else{
                printf("error:led state must be ON or OFF");
                return 0;
            }
        }else{
            printf("unkonow commond\n");
            printf("useage:\n./hello fan_level [0-100]\n./hello led ON/OFF \n");
            return 0;
        }

    }else{
        //*没有手动输入，则自动初始化*//
        ret = SendEvent(serv, E53_IA1_Start,NULL,0);
        printf("==> E53_IA1_Start = %d \n", ret);
    }
    MQTTDemoTask();//调用mqtt，连接华为云上传数据
    HdfIoServiceRecycle(serv);
    return 0;
}

